# This is a sample Python script.

# Press Shift+F10 to execute it or replace it with your code.
# Press Double Shift to search everywhere for classes, files, tool windows, actions, and settings.
import struct
import sys

import serial
import serial.tools.list_ports
from app.main_iic import *
import time

from threading import Thread
import keyboard


class ser_comm():
    def __init__(self, com, bps, timeout):
        self.port = com
        self.bps = bps
        self.timeout = timeout
        try:
            ser = serial.Serial(self.port, self.bps, timeout=self.timeout)
            if ser.is_open:
                logMgr.print('ser init true')
            else:
                logMgr.print('ser init false')
        except:
            logMgr.print('ser init false')
        pass


def get_ser_list():
    port_list = serial.tools.list_ports.comports()
    logMgr.print(f'valid ser {len(port_list)}')
    if len(port_list) == 0:
        logMgr.print('无可用串口')
    else:
        for i in range(0, len(port_list)):
            logMgr.print(port_list[i])


def ser_monitor():
    pass


def get_serial_port():
    pass


class RegAddr():
    def __init__(self, addr, bytecnt, name, datalen=2):
        self.addr = addr
        self.bytecnt = bytecnt
        self.name = name
        self.datalen = datalen  # 默认2个字节为一个数据


class RespData():
    def __init__(self, addr, srcDataArr, extras=None):
        self.addr = addr
        self.srcDataArr = srcDataArr
        self.extras = extras


class input_thread(Thread):  # 键盘处理类
    def __init__(self, iic_odj=None):
        super(input_thread, self).__init__()
        if iic_odj:
            self.iic_obj = iic_odj

    def run(self):
        # self.keyboardListener()
        # return
        cnts = 0
        cntc = 0
        self.save = False
        self.clear = False
        saving = False
        clearing = False
        while True:
            # r = keyboard.read_key()
            # print(r)
            k = keyboard.on_release_key('ctrl', self.iic_obj.data_set_save)
            # k = keyboard.on_release_key('ctrl+r', lambda x: os.system('cls'))
            # s = keyboard.is_pressed("ctrl+s")
            # #print(s)
            # if s:
            #     cnts+=1
            #     #print(cnts)
            #     if cnts/10 > 1:
            #         if self.save:
            #             print('关闭保存')
            #             self.save = False
            #         else:
            #             print('开启保存')
            #             self.save = True
            #             ts = time.strftime("%Y_%m_%d_%H_%M_%S")
            #             self.iic_obj.data_log = f'{ts}.txt'
            #         self.iic_obj.save = self.save
            #         cnts = 0
            # c = keyboard.is_pressed("ctrl+r")
            # if c:
            #     cntc += 1
            #     #print(cntc)
            #     if cntc / 10 > 1:
            #         print('开始清屏')
            #         self.clear = True
            #         cntc = 0
            # if self.clear and not clearing:
            #     clearing = True
            #     os.system('cls')
            #     self.iic_obj.databuff = []
            #     self.clear = False
            #     clearing = False
            #     print('清屏完成')
            time.sleep(0.01)
            # break


funaddr = {'version_addr': RegAddr(0x01, 6, "版本寄存器", datalen=1),
           'version_date_addr': RegAddr(0x07, 10, "版本日期寄存器", datalen=1),
           'ir_adc_addr': RegAddr(0x11, 3, "IR原始数据寄存器"),  # 1字节状态+2字节数据
           'ntc_adc_addr': RegAddr(0x13, 3, "NTC原始数据寄存器"),  # 1字节状态+2字节数据
           'obj_temp_addr': RegAddr(0x15, 3, "目标温度寄存器"),  # 1字节状态+2字节数据
           'env_temp_addr': RegAddr(0x17, 3, "环境温度寄存器"),  # 1字节状态+2字节数据
           'state_indicator_addr': RegAddr(0x27, 2, "标定状态指示寄存器",datalen=1),
           'slave_addr': RegAddr(0x2b, 1, "从机地址寄存器", datalen=1),
           'emit_ration_addr': RegAddr(0x2C, 4, "发射功率寄存器",datalen=1)}
calReg = {
    'calvalue_k': (0x19, 4),
    'calvalue_b': (0x1D, 4),
    'cal_point_1_adc': (0x21, 2),
    'cal_point_2_adc': (0x23, 2),
    'cal_ntc_adc': (0x25, 2),
    'cal_sta': (0x27, 2),
    'cal_obj_temp': (0x29, 2)
}


class iic_process(USBI2C):

    def __init__(self, usb_dev=0, i2c_dev=0x5c, commfreq=0x82, callback=None):
        logMgr.print('iic_process init')
        super(iic_process, self).__init__(usb_dev, i2c_dev, commfreq, callback)
        self.dev_list = []
        self.dev_connected = False
        self.running = False
        self.f = ''
        self.save = False
        self.regaddr = {'slave_addr': 0x2b, 's_work_mode': 0x00, 's_ir_data': 0x11}
        for k in funaddr.keys():
            self.regaddr[k] = funaddr[k].addr
        self.read_interval_mills = 1000

    def start_nnew_th(self, func, args):
        if not self.running:
            th = Thread(target=func, args=args)
            th.start()

    def init_config(self):
        if self.usb_init:
            self.set_usb_freq(0x80)
            self.__iic_dev_trace()

    def __iic_dev_trace(self):

        addr = self.scanDevAddr()
        if addr != -1 and addr != 0xff:
            logMgr.print(f'dev {hex(addr)} exist!!!')
            self.dev_list.append(addr)
            self.setdev_addr(addr)
            # self.set_usb_freq(0x80)
            self.write(self.regaddr.get('s_work_mode'), 0x02)  # 传感器实时更新寄存器
            logMgr.print('detect mode '+ str(self.read(self.regaddr.get('s_work_mode'))))
            self.dev_connected = True
            if self.iic_callback is not None:
                self.iic_callback.onDevInit()
        else:
            logMgr.print('no dev exist!!!!!!')
            self.dev_connected = False

    def scanDevAddr(self):
        data = -1
        for x in range(iic_process.dev_addr_start, iic_process.dev_addr_end + 1):
            if x % 2 != 0:  # 过滤奇数地址
                continue
            if not self.usb_init:
                break
            self.setdev_addr(x)
            data = self.read(0x2b)
            if data == x:
                return data
            time.sleep(0.005)
        return data

    def detect_data_loop(self, reg, cntbyte, datalen=2):
        logMgr.print('detect_data_loop', self.dev_connected)
        self.running = True
        if self.iic_callback is not None:
            self.iic_callback.onStateOutput(msg="正在读取状态...")
        while self.running and self.dev_connected:
            # print('detect_data_loop', self.dev_connected,self)
            # print('detect_data_loop1')
            # 同步返回数据
            self.detect_data_once(reg, cntbyte, datalen=datalen)
            time.sleep(self.read_interval_mills * 1.0 / 1000)
            # print(master)
            # break

    def detect_data_once(self, reg, cntbyte, datalen=2):
        if not self.dev_connected:
            return

        hasStateByte = reg == 0x11 or reg == 0x13 or reg == 0x15 or reg == 0x17  # 是否有状态位
        data = self.readReg(reg, cntbyte, datatypelen=datalen, hasStateByte=hasStateByte)  # 读寄存器数据
        # print(data)

        respData = RespData(reg, data)
        if reg == self.regaddr.get("version_addr"):
            respData.extras = self.parseVer(data)
        elif reg == self.regaddr.get("version_date_addr"):
            respData.extras = self.parseVerDate(data)
        elif reg == self.regaddr.get("ir_adc_addr") or reg == self.regaddr.get(
                "ntc_adc_addr") or reg == self.regaddr.get("obj_temp_addr") or reg == self.regaddr.get("env_temp_addr"):
            respData.extras = self.parseIRAdc(data)
        elif reg == self.regaddr.get("slave_addr"):
            respData.extras = self.parseSlaveAddr(data)
        elif reg == self.regaddr.get("emit_ration_addr"):
            datab = struct.unpack('<f',bytes(data))
            respData.extras = '%.1f' % datab[0]
        elif reg==self.regaddr.get("state_indicator_addr"):
            sta="[未标定]"
            if data[0]+data[1]==0xff:
                sta="[已标定]"
            respData.extras=str(hex(data[0]))+" "+str(hex(data[1]))+" "+sta
        else:
            respData.extras = str(respData.srcDataArr)

            # funaddr = {'version_addr': RegAddr(0x01, 6, "版本寄存器",datalen=1),
            #            'version_date_addr': RegAddr(0x07, 10, "版本日期寄存器"),
            #            'ir_adc_addr': RegAddr(0x11, 3, "IR原始数据寄存器"),  # 1字节状态+2字节数据
            #            'ntc_adc_addr': RegAddr(0x13, 3, "NTC原始数据寄存器"),  # 1字节状态+2字节数据
            #            'obj_temp_addr': RegAddr(0x15, 3, "目标温度寄存器"),  # 1字节状态+2字节数据
            #            'env_temp_addr': RegAddr(0x17, 3, "环境温度寄存器"),  # 1字节状态+2字节数据
            #            'state_indicator_addr': RegAddr(0x27, 2, "标定状态指示寄存器"),
            #            'slave_addr': RegAddr(0x2b, 1, "从机地址寄存器"),
            #            'emit_ration_addr': RegAddr(0x2C, 4, "发射功率寄存器")}

        if self.iic_callback is not None:
            self.iic_callback.onReceived(respData)

    def detect_data_stop(self):
        self.running = False
        if self.iic_callback is not None:
            self.iic_callback.onStateOutput(msg="暂停读取")

    def input_monitor(self):
        self.t = input_thread(self)
        self.t.start()

    # def mkdir(self,path):
    #     print('创建数据保存文件夹')
    #     path = path.strip()
    #     path = path.rstrip("\\")
    #     isExists = os.path.exists(path)
    #     if not isExists:
    #         os.makedirs(path)
    #         print(path+' 创建成功')#' 创建成功'
    #         return True
    #     else:
    #         # 如果目录存在则不创建，并提示目录已存在
    #         print(path + ' 目录已存在')
    #         return False
    def data_set_save(self, x):
        if self.save:
            self.save = False
            logMgr.print('关闭保存')
        else:
            self.save = True
            ts = time.strftime("%Y_%m_%d_%H_%M_%S")
            self.data_log = ts
            logMgr.print('开启保存 ', ts)

    def data_save(self, file, data):
        with open(f'.\log\{file}', 'a+') as f:
            f.writelines(str(data) + '\n')

    def init_console(self):
        logMgr.print('ctrl+s:保存，ctrl+r:清屏')
        logMgr.print('[状态位, ir_adc, ntc_adc, 物温, 环温]')

    def parseVer(self, data):
        vl = [chr(x) for x in data]
        v = ''.join(vl)
        return v

    def parseVerDate(self, data):
        vl = [chr(x) for x in data]
        v = ''.join(vl)
        print(v)
        return v

    def parseIRAdc(self, data):
        if data:
            if data[0] == 170:
                return str(data[1])
            else:
                return 'invalid data'

    def parseSlaveAddr(self, data):
        return str(hex(data[0]))

    def calMode(self):
        self.write(self.regaddr.get('s_work_mode'), 0x04)  # 切换为手动采样模式
        if self.read(self.regaddr.get('s_work_mode')) == 0x04:
            logMgr.print("进入标定模式")
            return True
        else:
            logMgr.print("进入标定模式失败", level='e')
            return False

    def exitCalMode(self):
        self.write(self.regaddr.get('s_work_mode'), 0x02)  # 切换为自动采样模式
        if self.read(self.regaddr.get('s_work_mode')) == 0x02:
            logMgr.print("退出标定模式")
            return True
        else:
            logMgr.print("退出标定模式失败", level='e')
            return False

    def calFirst(self):
        self.write(self.regaddr.get('s_work_mode'), 0x08)  # 标定第一点
        res = self.read(self.regaddr.get('s_work_mode'))
        if res == 0x08:
            logMgr.print("第一点标定成功")
            return True
        else:
            logMgr.print("第一点标定失败", level='e')
            return False

    def calSecond(self):
        self.write(self.regaddr.get('s_work_mode'), 0x10)  # 标定第二点
        if self.read(self.regaddr.get('s_work_mode')) == 0x10:
            logMgr.print("第二点标定成功")
            return True
        else:
            logMgr.print("第二点标定失败", level='e')
            return False

    def getCalParams(self):
        # 'calvalue_k':		(0x19,4),
        # 'calvalue_b':		(0x1D,4),
        # 'cal_point_1_adc':	(0x21,2),
        # 'cal_point_2_adc':	(0x23,2),
        # 'cal_ntc_adc':		(0x25,2),
        # 'cal_sta':			(0x27,2),
        # 'cal_obj_temp':		(0x29,2),

        res = ""
        data = self.read(calReg.get("calvalue_k")[0], calReg.get("calvalue_k")[1])
        datak = struct.unpack('<f',bytes(data))
        res += "k-->"
        res += str(datak[0])
        res += "\n"

        data = self.read(calReg.get("calvalue_b")[0], calReg.get("calvalue_b")[1])
        datab = struct.unpack('<f',bytes(data))
        res += "b-->"
        res += str(datab[0])
        res += "\n"

        data = self.readReg(calReg.get("cal_point_1_adc")[0], calReg.get("cal_point_1_adc")[1])
        res += "p1_adc-->"
        res += str(data[0])
        res += "\n"

        data = self.readReg(calReg.get("cal_point_2_adc")[0], calReg.get("cal_point_2_adc")[1])
        res += "p2_adc-->"
        res += str(data[0])
        res += "\n"

        data = self.readReg(calReg.get("cal_ntc_adc")[0], calReg.get("cal_ntc_adc")[1])
        res += "ntc_adc-->"
        res += str(data[0])
        res += "\n"

        data = self.read(calReg.get("cal_sta")[0], calReg.get("cal_sta")[1])
        res += "sta-->"
        res += str(data)
        res += "\n"

        data = self.read(calReg.get("cal_obj_temp")[0], calReg.get("cal_obj_temp")[1])
        res += "cal_obj_temp-->"
        res += str(data)
        res += "\n"

        return res
    def fun_cal_obj_temp(self,pt1 = None,pt2 = None):
        regname = 'cal_obj_temp'
        v = calReg.get(regname)
        if pt1 != None and pt2 != None:
            data = []
            data.append(pt1 & 0xff)
            data.append(pt2 & 0xff)
            print('set cal_obj_temp ',data)
            self.writeArr(v[0], dat=data)

    def fun_emit_ratio(self,r):
        arr=struct.pack('<f',r)
        bytesArr=[]
        for b in arr:
            bytesArr.append(b)
        self.writeArr(0x2C, dat=bytesArr)

    # def fun_get_cal_k(self):
    #     print(sys._getframe().f_code.co_name)
    #     time.sleep(self.iic_interval)
    #     data = self.read_reg('calvalue_k')
    #     print(data)
    #     data = struct.unpack('<f',bytes(data))
    #     print(data)
    #     return data[0]
    #     pass
    #
    # def fun_get_cal_b(self):
    #     print(sys._getframe().f_code.co_name)
    #     time.sleep(self.iic_interval)
    #     data = self.read_reg('calvalue_b')
    #     print(data)
    #     data = struct.unpack('<f',bytes(data))
    #     print(data)
    #     return data[0]
    #     pass

dev_monitor_enable = True


def iic_dev_monitor(iic_obj):
    # global iic_obj
    if iic_obj is None:
        iic_obj = iic_process()
    logMgr.print('iic_dev_monitor')
    while dev_monitor_enable:
        while dev_monitor_enable and not iic_obj.dev_connected:  # iic
            logMgr.print('dev_connected ng')
            while dev_monitor_enable and not iic_obj.usb_init:  # usb
                logMgr.print('usb init ng')
                iic_obj.initUSB()  # 重新尝试连接USB
                time.sleep(1)
            # print('usb init ok')
            iic_obj.init_config()
            time.sleep(1)
        # print('iic connect ok')
        # print(master)
        time.sleep(1)
        # print("持续检测中")
        # print('master.dev_connected!!!!!!! ',master.dev_connected)


def iic_dev_thread(iic_obj):
    th = Thread(target=iic_dev_monitor, args=(iic_obj,))
    th.start()
# if __name__ == '__main__':
# print_hi('PyCharm')
# global master
# master_bak = None
# ver = 'I2C Data Process, v1.1, 20200119 by fatri_xm'
# print(ver)
# #get_ser_list()
# master = iic_process()
# iic_dev_thread()
# while True:
#     if master_bak != master and master.dev_connected: #matser对象随着usb拔插改变，所以需要监控master对象
#         master_bak = master
#         master.init_console()
#         print('start detect')
#         master.input_monitor()
#         master.mkdir('.\log')
#         #master.detect_data_loop(0x11,9)
#         master.start_nnew_th(master.detect_data_loop,(master.regaddr.get('s_ir_data'),9))
data=[0x6f, 0x13, 0x31, 0xc0]
datak = struct.unpack('<f',bytes(data))
print(datak)